#include <iostream>
#include <unistd.h>
#include <string>
#include <string.h>
#include <cassert>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>

using namespace std;

int main()
{
    mkfifo("tp",0644);
    int infd=open("tp",O_RDONLY);
    if(infd == -1)
    {
        perror("infd open");
        exit(-1);
    }
    int outfd=open("tp",O_WRONLY);
    if(outfd == -1)
    {
        perror("outfd open");
        exit(-2);
    }
    char buffer[1024]={0};
    int s=0;
    while(s=read(infd,buffer,strlen(buffer)) > 0)
    {
        write(outfd,buffer,strlen(buffer));
    }
    close(infd);
    close(outfd);
    return 0;
}
// int main()
// {
//     mkfifo("tp",0644);
//     int infd;
//     //这里只以读的方式打开
//     infd=open("tp",O_RDONLY);
//     if(infd==-1)
//     {
//         ERR_EXIT("open");
//     }

//     int outfd;
//     outfd=open("tp",O_WRONLY);
//     if(outfd==-1)
//     {
//         ERR_EXIT("open");
//     }
//     char buffer[1024]={0};
//     while(read(infd,buffer,strlen(buffer)) > 0)
//     {
//         write(outfd,buffer,strlen(buffer));
//     }
//     close(infd);
//     close(outfd);
//     return 0;
// }
//利用命名管道实现文件拷贝
// int main(int argc,char* argv[])
// {
//     mkfifo("tp",0644);
//     int infd=open("abc",O_RDONLY);
//     if(infd==-1)
//     {
//         perror("open");
//         exit(-1);
//     }
//     int outfd;
//     outfd=open("tp",O_WRONLY);
//     if(outfd==-1)
//     {
//         perror("open");
//         exit(-2);
//     }
//     char buffer[1024]={0};
//     ssize_t s=read(infd,buffer,strlen(buffer));
//     while(s > 0)
//     {
//         write(outfd,buffer,strlen(buffer));
//     }
//     close(infd);
//     close(outfd);
//     return 0;
// }

/*
管道的读写规则：
当没有数据可以读的时候
read：调用阻塞，进程暂停进行，一直等到有数据来的时候
管道的特点：
只能用于具有共同祖先的进程之间通信，通常一个管道由一个进程
创建，然后调用fork之后，父子进程之间就可以公用管道
//当然如果我们想要对没有共同祖先的进程也就是没有亲缘关系的进程
之间建立管道通信的话，就必须使用FIFO建立命名管道
命名管道可以从命令行上面建立
mkfifo filename 可以建立命名管道
int mkfifo(const char* filename,mode_t mode)
成功的话返回0，失败的话返回错误码
*/
//创建命名管道
/*
匿名管道与命名管道的区别
匿名管道由pipe函数创建并且打开
命名管道由mkfifo函数创建打开的话必须使用open
他们二人唯一的不同就在于他们创建与打开的区别不同，一旦打开以后
他们就具有相同的语义
*/
// int main()
// {
//     mkfifo("pipe_to",0644);
//     return 0;
// }
// int main(int argc,char* argv[])
// {
//     int pipefd[2]={0};
//     int n=pipe(pipefd);
//     assert(n!=-1);
    
//     pid_t id=fork();
//     if(id == -1)
//     {
//         perror("fork");
//         exit(-1);
//     }
//     else if(id == 0)
//     {
//         close(pipefd[0]);
//         write(pipefd[1],"hello",strlen("hello"));
//         close(pipefd[1]);
//     }
//     else
//     {
//         close(pipefd[1]);
//         char buffer[20]={0};
//         read(pipefd[0],buffer,strlen(buffer));
//         cout<<"buffer:"<<buffer<<endl;
//     }
//     return 0;
// }

// int main(int argc, char *argv[])
// {
//     int pipefd[2];
//     if (pipe(pipefd) == -1)
//         ERR_EXIT("pipe error");

//     int main(int argc, char *argv[])
//     {
//         int pipefd[2] = {0};
//         int pipefd[2] = {0};
//         int n = pipe(pipefd);
//         assert(n != -1);
//         pid_t pid;
//         pid = fork();
//         if (pid == -1)
//             perror("fork");
//         if (pid == 0)
//         {
//             close(pipefd[0]);
//             write(pipefd[1], "hello", 5);
//             close(pipefd[1]);
//             exit(EXIT_SUCCESS);
//         }
//         close(pipefd[1]);
//         char buf[10] = {0};
//         read(pipefd[0], buf, 10);
//         printf("buf=%s\n", buf);

//         return 0;
//     }
    // int main()
    // {
    //     int pipefd[2] = {0};
    //     int n = pipe(pipefd);
    //     assert(n != -1);
    //     pid_t id = fork();
    //     if (id == -1)
    //     {
    //         perror("fork");
    //     }
    //     if (id == 0)
    //     {
    //         close(pipefd[0]);
    //         write(pipefd[1], "hello yangyi", strlen("hello yangyi"));
    //         close(pipefd[1]);
    //         exit(EXIT_SUCCESS);
    //     }
    //     close(pipefd[1]);
    //     char buffer[20] = {0};
    //     read(pipefd[0], buffer, strlen(buffer));
    //     cout << buffer << endl;
    //     return 0;
    // }
    // int main()
    // {
    //     int pipefd[2]={0};
    //     pid_t id=fork();
    //     if(id == -1)
    //     {
    //         /*
    //         #define ERR_EXIT(m)
    //         do
    // 	    {
    // 		    perror(m);
    // 		    exit(EXIT_FAILURE);
    // 	    }while(0)
    //         */
    //        //这是一个错误宏定义
    //         ERR_EXIT("fork error");
    //     }
    //     if(id == 0)
    //     {
    //         //子进程进行写入然后让父进程进行读取
    //         close(pipefd[0]);
    //         write(pipefd[1],"hello",strlen("hello"));
    //         close(pipefd[1]);
    //         exit(EXIT_SUCCESS);
    //     }
    //     close(pipefd[1]);
    //     char buffer[10]={0};
    //     ssize_t s=read(pipefd[0],buffer,strlen(buffer));
    //     if(s < strlen(buffer))
    //     {
    //         perror("read error");
    //         exit(-1);
    //     }
    //     cout<<buffer<<endl;
    //     return 0;
    // }
    // int main()
    // {
    //     int pipefd[2]={0};
    //     int n=pipe(pipefd);
    //     assert(n!=-1);
    //     char buffer[100];

    //     while(fgets(buffer,100,stdin))
    //     {
    //         int len=strlen(buffer);
    //         int ret=write(pipefd[1],buffer,len);
    //         if(ret!=len)
    //         {
    //             perror("write to pipe");
    //             break;
    //         }
    //         memset(buffer,0x00,len);
    //         ssize_t s=read(pipefd[0],buffer,len);
    //         if(s != len)
    //         {
    //             perror("read from pipe");
    //             break;
    //         }
    //         int res=write(1,buffer,len);
    //         if(res != len)
    //         {
    //             perror("write to stdout");
    //             break;
    //         }
    //     }
    //     return 0;
    // }
    // int main()
    // {
    //     int pipefd[2]={0};
    //     int n=pipe(pipefd);
    //     assert(n!=-1);
    //     char buffer[10]={0};

    //     while(fgets(buffer,10,stdin))
    //     {
    //         //write to pipe
    //         int len=strlen(buffer);
    //         int ret1=write(pipefd[1],buffer,len);
    //         if(ret1 != len)
    //         {
    //             perror("write to pipe");
    //             break;
    //         }
    //         memset(buffer,0x00,sizeof(buffer));
    //         //read from pipe
    //         ssize_t s=read(pipefd[0],buffer,len);
    //         if(s != len)
    //         {
    //             perror("read from pipe");
    //             break;
    //         }
    //         //write to stdout
    //         //记住这里一定要写标准输出，标准输入输出只能用0或者1代替
    //         int ret2=write(1,buffer,strlen(buffer));
    //         if(ret2 != len)
    //         {
    //             perror("write to stdout");
    //             break;
    //         }
    //     }
    //     return 0;
    // }
    // int main()
    // {
    //     int pipefd[2]={0};
    //     int n=pipe(pipefd);
    //     assert(n!=-1);
    //     char buffer[100]={0};

    //     while(fgets(buffer,100,stdin))
    //     {
    //         int ret=write(pipefd[1],buffer,strlen(buffer));
    //         if(ret != strlen(buffer))
    //         {
    //             perror("write to pipe");
    //             break;
    //         }
    //         memset(buffer,0x00,strlen(buffer));

    //         int res=read(pipefd[0],buffer,strlen(buffer));
    //         if(ret != strlen(buffer))
    //         {
    //             perror("read to pipe");
    //             break;
    //         }

    //         int rel=write(pipefd[1],buffer,strlen(buffer));
    //         if(rel != strlen(buffer))
    //         {
    //             perror("write to stdout");
    //             break;
    //         }
    //     }
    //     return 0;
    // }
    // int main(void)
    // {
    //     int fds[2];
    //     char buf[100];
    //     int len;
    //     if (pipe(fds) == -1)
    //         perror("make pipe"), exit(1);
    //     // read from stdin
    //     while (fgets(buf, 100, stdin))
    //     {
    //         len = strlen(buf);
    //         // write into pipe
    //         if (write(fds[1], buf, len) != len)
    //         {
    //             perror("write to pipe");
    //             break;
    //         }
    //         memset(buf, 0x00, sizeof(buf));

    //         // read from pipe
    //         if ((len = read(fds[0], buf, 100)) == -1)
    //         {
    //             perror("read from pipe");
    //             break;
    //         }
    //         // write to stdout
    //         if (write(1, buf, len) != len)
    //         {
    //             perror("write to stdout");
    //             break;
    //         }
    //     }
    // }
    // int main()
    // {
    //     int pipefd[2]={0};
    //     char buffer[100];
    //     int n=pipe(pipefd);
    //     assert(n != -1);

    //     //fgets函数返回的是一个char*指针，如果失败返回空指针
    //     while(fgets(buffer,100,strlen(buffer)))
    //     {
    //         //write函数再写入后会返回字节数，如果等于0则表示
    //         //未写入内容
    //         int ret=write(pipefd[1],buffer,strlen(buffer));
    //         if(ret != strlen(buffer))
    //         {
    //             perror("write to pipe");
    //             break;
    //         }
    //         //这里的设计思路是先写入到管道当中然后再从管道当中
    //         //读取
    //     }
    //     memset(buffer,0x00,strlen(buffer));
    //     int res=write(1,buffer,strlen(buffer));
    //     if(res != strlen(buffer))
    //     {
    //         perror("write to stdout");
    //         break;
    //     }
    //     return 0;
    // }
    // int main()
    // {
    //     int fd[2]={0};
    //     char buffer[100];
    //     int len;
    //     int n=pipe(fd);
    //     if(n == -1)
    //     {
    //         perror("make pipe");
    //         exit(-1);
    //     }
    //     //read from stdin
    //     //fgets函数以\0作为终止，或者读到本行结尾或者EOF的时候才会停止，读取少于n个字节
    //     //(第二个参数)
    //     while(fgets(buffer,100,stdin))
    //     {
    //         len=strlen(buffer);
    //         //write into pipe
    //         int ret=write(fd[1],buffer,len);
    //         if(ret != len)
    //         {
    //             perror("write");
    //             break;
    //         }
    //         //这个函数使用常量字节填充buffer执行的内存区域的前sizeof(buffer)个字节,
    //         //这个函数返回的一个指针，指向buffer所在的区域的首地址
    //     }
    //     memset(buffer,0x00,sizeof(buffer));

    //     //read from pipe
    //     ssize_t s=read(fd[0],buffer,len);
    //     if(s != len)
    //     {
    //         perror("read");
    //         exit(-2);
    //     }

    //     //write to stdout
    //     int ret2=write(1,buffer,len);
    //     if(ret2 != len)
    //     {
    //         perror("write ro stdout");
    //         exit(-3);
    //     }
    //     return 0;
    // }
    /*
    进程间通信的目的：
    数据传输：一个进程需要将它的数据发送给另外一个进程
    资源共享：多个进程之间共享同样的资源
    通知事件：一个进程需要向另一个或另一组进程发送消息，通知他们
    发生了某些事件
    进程控制：有些进程希望完全控制另外一个进程的执行，此时控制进程
    希望能够拦截另外一个进程的所有陷入和异常，并能够及时知道它的状态

    管道：我们把进程连接到另外一个进程的数据流称为管道
    #include<unistd.h>
    int pipe(int fd[2])
    fd:文件描述符组。其中0代表着读端1代表着写端
    成功返回0，失败返回错误码
    */
    // 实例：从键盘当中读取数据写入管道，再读取管道写入到屏幕